/*
 * MIT License
 *
 * Copyright (c) 2020 wen.gu <454727014@qq.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

 /******************************************************************************
 * Name: dog_json_reader.cpp
 *
 * Purpose: json reader implementation
 *
 * Developer:
 *   wen.gu , 2020-08-19
 *
 * TODO:
 *
 ******************************************************************************/

 /******************************************************************************
 **    INCLUDES
 ******************************************************************************/
#define LOG_TAG "JsRd"
#include "dog_json.h"

#include <stack>
#include <sstream>

#include "dog_log.h"

namespace dog
{

/******************************************************************************
 **    MACROS
 ******************************************************************************/

/******************************************************************************
 **    VARIABLE DEFINITIONS
 ******************************************************************************/

enum class MyState: uint8_t   /** layer 1 state type */
{
    None = 0,
    Start,
    Object,
    Array,
    Error,
    End
};

enum class ObjectState: uint8_t  /** layer 2 state type */
{
    Start = 0,
    MemberKey,
    KeyValueDelimiter,
    NormalValue,
    MemberDelimiter,
    End,
};

enum class ArrayState : uint8_t  /** layer 2 state type */
{
    Start = 0,
    Element,
    ElementDelimiter,
    End,
};

typedef enum eTokenType
{
    None = 0,
    ObjectStart = '{',
    ObjectEnd = '}',
    ArrayStart = '[',
    ArrayEnd = ']',
    KeyValueDelimiter = ':',
    MemberDelimiter = ',',
    StringStart = '"',
}TokenType;

using ValueNodes = std::stack<Value*>;

struct ReadState
{
    MyState state = MyState::None;
    ObjectState objState = ObjectState::Start;
    ArrayState arrayState = ArrayState::Start;
public:
    ReadState(MyState ms = MyState::None):state(ms){}
};

class MyReader3
{
public:
    bool parse(const char* pStart, const char* pEnd, Value& root);
private:
    ReadState onStart(const char*& pStart, const char* pEnd);
    ReadState onObject(ReadState& lastState, const char*& pStart, const char* pEnd);
    ReadState onArray(ReadState& lastState, const char*& pStart, const char* pEnd);
    ReadState onError(const char*& pStart, const char* pEnd);

private:
    inline Value& currentValue()
    {
        return *(mNodes.top());
    }

    inline void pushValue(Value& val)
    {
        mNodes.push(&val);
    }

    inline void popValue()
    {
        mNodes.pop();
    }

    inline bool currentIsRoot()
    {
        return mNodes.top() == mRootValue;
    }

private:
    void readArrayElement(const char*& pStart, const char* pEnd, ReadState& rs);
private:
    bool mIsErrorOccur = false;
    Value* mLastValue = nullptr;
    Value* mRootValue = nullptr;
    ValueNodes mNodes;
    std::string mErrorDesc = "";
};

/******************************************************************************
 **    inner FUNCTION DEFINITIONS
 ******************************************************************************/

static inline void SkipSpaces(const char*& pStart, const char* pEnd)
{
    while (pStart < pEnd)
    {
        char c = *pStart;
        if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
        {
            ++pStart;
        }
        else
        {
            break;
        }
    }
}

static inline char GetNextChar(const char*& pStart, const char* pEnd)
{
    if (pStart < pEnd)
    {
        return *pStart++;
    }

    return 0;
}

static inline bool StrMatch(const char*& pStart, const char* pEnd,
    const char* pattern, int patternLength)
{
    if ((pEnd - pStart) < patternLength)
    {
        return false;
    }

    int index = patternLength;
    while (index--)
    {
        if (pStart[index] != pattern[index])
        {
            return false;
        }
    }

    pStart += patternLength;
    return true;
}

inline std::string CodePointToUTF8(uint32_t cp)
{
    std::string result;

    // based on description from http://en.wikipedia.org/wiki/UTF-8

    if (cp <= 0x7f)
    {
        result.resize(1);
        result[0] = static_cast<char>(cp);
    }
    else if (cp <= 0x7FF)
    {
        result.resize(2);
        result[1] = static_cast<char>(0x80 | (0x3f & cp));
        result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
    }
    else if (cp <= 0xFFFF)
    {
        result.resize(3);
        result[2] = static_cast<char>(0x80 | (0x3f & cp));
        result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
        result[0] = static_cast<char>(0xE0 | (0xf & (cp >> 12)));
    }
    else if (cp <= 0x10FFFF)
    {
        result.resize(4);
        result[3] = static_cast<char>(0x80 | (0x3f & cp));
        result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
        result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
        result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
    }

    return result;
}

bool DecodeUnicodeEscapeSequence(const char*& pStart, const char* pEnd, uint32_t& ret_unicode)
{
    if ((pEnd - pStart) < 4)
    {
        LOGE("Bad unicode escape sequence in string: four digits expected:%s.", pStart);
        return false;
    }

    int unicode = 0;
    for (int index = 0; index < 4; ++index)
    {
        char c = *pStart++;
        unicode *= 16;
        if ((c >= '0') && (c <= '9'))
        {
            unicode += c - '0';
        }
        else if ((c >= 'a') && (c <= 'f'))
        {
            unicode += c - 'a' + 10;
        }
        else if ((c >= 'A') && (c <= 'F'))
        {
            unicode += c - 'A' + 10;
        }
        else
        {
            LOGE("Bad unicode escape sequence in string: hexadecimal digit expected: %s.", pStart);
        }
    }
    ret_unicode = static_cast<unsigned int>(unicode);
    return true;
}


bool DecodeUnicodeCodePoint(const char*& pStart, const char* pEnd, uint32_t& unicode)
{

    if (!DecodeUnicodeEscapeSequence(pStart, pEnd, unicode))
    {
        return false;
    }

    if ((unicode >= 0xD800) && (unicode <= 0xDBFF))
    {
        // surrogate pairs
        if ((pEnd - pStart) < 6)
        {
            LOGE("additional six characters expected to parse unicode surrogate pair:%s\n",
                pStart);
        }

        if (*(pStart++) == '\\' && *(pStart++) == 'u')
        {
            unsigned int surrogatePair;
            if (DecodeUnicodeEscapeSequence(pStart, pEnd, surrogatePair))
            {
                unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
            }
            else
            {
                return false;
            }
        }
        else
        {
            LOGE("expecting another \\u token to begin the second half of "
                "a unicode surrogate pair: %s\n", pStart);
        }
    }

    return true;
}




static bool ReadString(const char*& pStart, const char* pEnd, std::string& str)
{
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
    static const unsigned char escape[256] = {
        Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/',
        Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0,
        0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0,
        0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16
    };
#undef Z16
    str.clear();

    unsigned char ch = '\0';
   // const char* strStart = pStart;
    while (pStart < pEnd)
    {
        ch = GetNextChar(pStart, pEnd);
        if (ch == '\\')
        {
            unsigned char e = GetNextChar(pStart, pEnd);

            if (escape[e] != 0)
            {
                str.append(1, escape[e]);
            }
            else if (e == 'u')
            {/** todo parse unicode */
                str.append(1, ch); /** add '\\' */
                //str.append(1, e);

                uint32_t unicode;
                if (!DecodeUnicodeCodePoint(pStart, pEnd, unicode))
                {
                    return false;
                }

                str += CodePointToUTF8(unicode);
            }
            else
            {
                LOGE("Illegal backslash escape: '\\%c' \n", e);
                break;
            }
        }
        else if (ch == '"')
        {
            break;
        }
        else if (static_cast<unsigned>(ch) < 0x20)
        {// RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
            LOGE("now(code:%d), unescaped = %%x20-21 / %%x23-5B / %%x5D-10FFFF\n", ch);
            break;
        }
        else
        {
            str.append(1, ch);
        }
    }

    if (ch == '"')
    {
        return true;
    }
    else
    {
        str.clear();
    }

    return false;
}

#if 0
static bool ReadString(const char*& pStart, const char* pEnd)
{
    char ch = '\0';
    //const char* strStart = pStart;
    while (pStart < pEnd)
    {
        ch = GetNextChar(pStart, pEnd);
        if (ch == '\\')
        {
            GetNextChar(pStart, pEnd);
        }
        else if (ch == '"')
        {
            break;
        }
        else if (static_cast<unsigned>(ch) < 0x20)
        {// RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
            break;
        }
    }

    if (ch == '"')
    {
        return true;
    }

    return false;
}
#endif

static bool DecodeDouble(const char*& pStart, const char* pEnd, Value& val)
{
    double value = 0;
    std::string buffer(pStart, pEnd);

    std::istringstream is(buffer);

    if (!(is >> value))
    {
        std::string numStr(pStart, pEnd);
        LOGE("'%s' is not a number\n", numStr.c_str());
        /** todo record error */
        return false;
    }

    val = value;
    return true;
}

bool DecodeNumber(const char*& pStart, const char* pEnd, Value& val)
{
    // Attempts to parse the number as an integer. If the number is
    // larger than the maximum supported value of an integer then
    // we decode the number as a double.
    const char* current = pStart;

    bool isNegative = *current == '-';

    if (isNegative)
    {
        ++current;
    }

    // TODO: Help the compiler do the div and mod at compile time or get rid of
    // them.
    Value::LargestUInt maxIntegerValue =
        isNegative ?
        (Value::LargestUInt(Value::maxLargestInt) + 1) : Value::maxLargestUInt;

    Value::LargestUInt threshold = maxIntegerValue / 10;
    Value::LargestUInt value = 0;

    while (current < pEnd)
    {
        char c = *current++;
        if ((c < '0') || (c > '9'))
        {
            return DecodeDouble(pStart, pEnd, val);
        }

        auto digit(static_cast<Value::UInt>(c - '0'));

        if (value >= threshold)
        {
            // We've hit or exceeded the max value divided by 10 (rounded down). If
            // a) we've only just touched the limit, b) this is the last digit, and
            // c) it's small enough to fit in that rounding delta, we're okay.
            // Otherwise treat this number as a double to avoid overflow.
            if ((value > threshold) || (current != pEnd) ||
                (digit > maxIntegerValue % 10))
            {
                return DecodeDouble(pStart, pEnd, val);
            }
        }
        value = value * 10 + digit;
    }

    if (isNegative && value == maxIntegerValue)
    {
        val = Value::minLargestInt;
    }
    else if (isNegative)
    {
        val = -Value::LargestInt(value);
    }
    else if (value <= Value::LargestUInt(Value::maxInt))
    {
        val = Value::LargestInt(value);
    }
    else
    {
        val = value;
    }

    return true;
}



static bool ReadNumber(const char*& pStart, const char* pEnd, Value& val)
{
    const char* numStart = pStart;
    bool isZeroFirst = false;
    bool hasFractional = false;
    char c = *pStart; // stopgap for already consumed character

    /** for sign character */
    if (c == '-')
    {
        ++pStart;
        c = '0';
    }
    else if (c == '0')
    {
        isZeroFirst = true;
    }

    // integral part
    while ((c >= '0') && (c <= '9'))
    {
        c = (pStart < pEnd) ? *pStart++ : '\0';
    }

    // fractional part
    if (c == '.')
    {
        hasFractional = true;
        c = (pStart < pEnd) ? *pStart++ : '\0';
        while ((c >= '0') && (c <= '9'))
        {
            c = (pStart < pEnd) ? *pStart++ : '\0';
        }
    }

    // exponential part
    if ((c == 'e') || (c == 'E'))
    {
        c = (pStart < pEnd) ? *pStart++ : '\0';
        if ((c == '+') || (c == '-'))
        {
            c = (pStart < pEnd) ? *pStart++ : '\0';
        }

        while ((c >= '0') && (c <= '9'))
        {
            c = (pStart < pEnd) ? *pStart++ : '\0';
        }
    }

    if ((numStart + 1) < pStart)
    {/** if have valid number string, then rollback one byte */
        --pStart;
        if (!hasFractional && isZeroFirst && ((pStart - numStart) > 1))
        {/** check (pStart - numStart) > 1,
          * is except the case of only one zero
          *
          */
            LOGE("Numbers(integer) cannot have leading zeroes\n");
            return false;
        }
        else
        {
            return DecodeNumber(numStart, pStart, val);
        }
    }

    return false;
}

#if 0
static bool ReadNumber(const char*& pStart, const char* pEnd)
{
    const char* p = pStart;
    char c = '0'; // stopgap for already consumed character
    // integral part
    while ((c >= '0') && (c <= '9'))
    {
        c = (pStart = p) < pEnd ? *p++ : '\0';
    }

    // fractional part
    if (c == '.')
    {
        c = (pStart = p) < pEnd ? *p++ : '\0';
        while ((c >= '0') && (c <= '9'))
        {
            c = (pStart = p) < pEnd ? *p++ : '\0';
        }

    }
    // exponential part
    if ((c == 'e') || (c == 'E'))
    {
        c = (pStart = p) < pEnd ? *p++ : '\0';
        if ((c == '+') || (c == '-'))
        {
            c = (pStart = p) < pEnd ? *p++ : '\0';
        }

        while ((c >= '0') && (c <= '9'))
        {
            c = (pStart = p) < pEnd ? *p++ : '\0';
        }

    }

    return true;
}
#endif

ValueType JsonReadValue(const char*& pStart, const char* pEnd, Value& val)
{
    SkipSpaces(pStart, pEnd);
    char ch = GetNextChar(pStart, pEnd);
    ValueType vt = ValueType::Error;

    switch (ch)
    {
    case '{':
    {
        val = Value(ValueType::Object);
        vt = ValueType::Object;
        break;
    }
    case '[':
    {
        val = Value(ValueType::Array);
        vt = ValueType::Array;
        break;
    }
    case '"':
    {
        std::string str = "";
        if (ReadString(pStart, pEnd, str))
        {
            val = str;
            vt = ValueType::String;
        }
        else
        {
            LOGE(" read string error failed\n");
        }
        break;
    }
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
    case '-':
    {
        --pStart; //rollback number
        if (ReadNumber(pStart, pEnd, val))
        {
            vt = val.type();
        }
        else
        {
            LOGE("read number value failed\n");
        }
        break;
    }
    case 't':
    {
        if (StrMatch(pStart, pEnd, "rue", 3))
        {
            vt = ValueType::Boolean;
            val = true;
        }
        else
        {
            LOGE("read boolean value: true, failed\n");
        }
        break;
    }
    case 'f':
    {
        if (StrMatch(pStart, pEnd, "alse", 4))
        {
            vt = ValueType::Boolean;
            val = false;
        }
        else
        {
            LOGE("read boolean value: false, failed\n");
        }
        break;
    }
    case 'n':
    {
        if (StrMatch(pStart, pEnd, "ull", 3))
        {
            vt = ValueType::Null;
            /** here do nothing, default as null value */
        }
        else
        {
            LOGE("read 'null' value, failed\n");
        }
        break;
    }
    default:
        LOGE("now(code:%d, %c), Syntax error: value, object or array expected.\n", ch, ch);
        break;
    }

    return vt;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
ReadState MyReader3::onStart(const char*& pStart, const char* pEnd)
{
    ReadState rs(MyState::Error);

    char ch = *pStart;
    ++pStart;

    if (ch == ObjectStart)
    {
        currentValue() = Value(ValueType::Object);
        rs.state = MyState::Object;
    }
    else if (ch == ArrayStart)
    {
        currentValue() = Value(ValueType::Array);
        rs.state = MyState::Array;
    }
    else
    {
        LOGE("now('%c'), Syntax error : object or array expected.\n", ch);
        /** set error */
    }

    return rs;
}

ReadState MyReader3::onObject(ReadState& lastState, const char*& pStart, const char* pEnd)
{
    ReadState rs = lastState;
    ObjectState& objState = rs.objState;

    while (rs.state == MyState::Object)
    {
        if (objState == ObjectState::Start)
        {
            SkipSpaces(pStart, pEnd);
            char ch = GetNextChar(pStart, pEnd);

            if (ch == StringStart)
            {
                objState = ObjectState::MemberKey;
            }
            else if (ch == ObjectEnd)
            {
                objState = ObjectState::End;
            }
            else
            {
                LOGE("now('%c'), Missing '}' or object member name(key)\n", ch);
                rs.state = MyState::Error;
            }
        }
        else if (objState == ObjectState::MemberKey)
        {
            std::string key = "";
            if (ReadString(pStart, pEnd, key))
            {
                SkipSpaces(pStart, pEnd);
                char ch = GetNextChar(pStart, pEnd);

                if (ch == KeyValueDelimiter)
                {
                    pushValue(currentValue()[key]);
                    objState = ObjectState::KeyValueDelimiter;
                }
                else
                {
                    LOGE("now('%c'), Missing ':' after object member name\n", ch);
                    rs.state = MyState::Error;
                }
            }
            else
            {
                LOGE("read the key of object member failed\n");
                rs.state = MyState::Error;
            }
        }
        else if (objState == ObjectState::KeyValueDelimiter)
        {
            ValueType vt = JsonReadValue(pStart, pEnd, currentValue());
            if (vt == ValueType::Object)
            {
                objState = ObjectState::Start; /** read next object value */
            }
            else if (vt == ValueType::Array)
            {
                rs.state = MyState::Array;
                rs.arrayState = ArrayState::Start;
            }
            else if (vt == ValueType::Error)
            {
                rs.state = MyState::Error;
            }
            else
            {
                popValue(); /** normal value, pop current value from stack */
                /** for normal value */
                objState = ObjectState::NormalValue;
            }
        }
        else if (objState == ObjectState::NormalValue)
        {
            SkipSpaces(pStart, pEnd);
            char ch = GetNextChar(pStart, pEnd);

            if (ch == MemberDelimiter)
            {
                objState = ObjectState::MemberDelimiter;
            }
            else if (ch == ObjectEnd)
            {
                objState = ObjectState::End;
            }
            else
            {
                LOGE("now('%c'), Missing ',' or '}' in object declaration\n", ch);
                rs.state = MyState::Error;
            }
        }
        else if (objState == ObjectState::MemberDelimiter)
        {
            SkipSpaces(pStart, pEnd);
            char ch = GetNextChar(pStart, pEnd);

            if (ch == StringStart)
            {
                objState = ObjectState::MemberKey;
            }
            else
            {
                LOGE("now('%c'), Missing object member name(key)\n", ch == '\0' ? '0' : ch);
                rs.state = MyState::Error;
            }
        }
        else if (objState == ObjectState::End)
        {
            if (currentIsRoot())
            {
                rs.state = MyState::End;
            }
            else
            {
                popValue();
                ValueType vt = currentValue().type();

                if (vt == ValueType::Object)
                {/** keep rs.state as MyState::Object, just update inner state */
                    objState = ObjectState::NormalValue; /** todo refine me? */
                }
                else if (vt == ValueType::Array)
                {
                    rs.state = MyState::Array;
                    rs.arrayState = ArrayState::Element; /** todo refine me? */
                }
                else
                {
                    /** only array or object can have member, so the other value type is */
                    LOGE("now value type(%d), Syntax error : object(%d) or array(%d) expected\n",
                        uint8_t(vt), uint8_t(ValueType::Object), uint8_t(ValueType::Array));
                    rs.state = MyState::Error;
                }
            }
        }
        else
        {
            rs.state = MyState::Error;
        }
    }

    return rs;
}

ReadState MyReader3::onArray(ReadState& lastState, const char*& pStart, const char* pEnd)
{
    ReadState rs = lastState;
    ArrayState& arrState = rs.arrayState;

    while (rs.state == MyState::Array)
    {
        if (arrState == ArrayState::Start)
        {
            SkipSpaces(pStart, pEnd);

            if (*pStart == ArrayEnd)
            {
                ++pStart; /** skip ']' */
                arrState = ArrayState::End;
            }
            else
            {
                readArrayElement(pStart, pEnd, rs);
            }
        }
        else if (arrState == ArrayState::Element)
        {
            SkipSpaces(pStart, pEnd);
            char ch = GetNextChar(pStart, pEnd);

            if (ch == MemberDelimiter)
            {
                arrState = ArrayState::ElementDelimiter;
            }
            else if (ch == ArrayEnd)
            {
                arrState = ArrayState::End;
            }
            else
            {
                LOGE("now('%c'), Missing ',' or ']' in array declaration\\n", ch);
                rs.state = MyState::Error;
            }
        }
        else if (arrState == ArrayState::ElementDelimiter)
        {
            readArrayElement(pStart, pEnd, rs);
        }
        else if (arrState == ArrayState::End)
        {
            if (currentIsRoot())
            {
                rs.state = MyState::End;
            }
            else
            {
                popValue();
                ValueType vt = currentValue().type();

                if (vt == ValueType::Object)
                {
                    rs.state = MyState::Object;
                    rs.objState = ObjectState::NormalValue; /** just as normal vlaue */
                }
                else if (vt == ValueType::Array)
                {/** keep rs.state as MyState::Array, just update inner state */
                    arrState = ArrayState::Element; /** todo refine me? */
                }
                else
                {
                    /** only array or object can have member, so the other value type is */
                    LOGE("now value type(%d), Syntax error : object(%d) or array(%d) expected\n",
                        uint8_t(vt), uint8_t(ValueType::Object), uint8_t(ValueType::Array));
                    rs.state = MyState::Error;
                }
            }
        }
        else
        {
            rs.state = MyState::Error;
        }
    }

    return rs;
}

ReadState MyReader3::onError(const char*& pStart, const char* pEnd)
{
    mIsErrorOccur = true;

    return ReadState(MyState::End);
}


void MyReader3::readArrayElement(const char*& pStart, const char* pEnd, ReadState& rs)
{
    pushValue(currentValue().append(Value()));
    ValueType vt = JsonReadValue(pStart, pEnd, currentValue());

    if (vt == ValueType::Array)
    {/** keep rs.state as MyState::Array, just update inner state */
        rs.arrayState = ArrayState::Start;
    }
    else if (vt == ValueType::Object)
    {
        rs.state = MyState::Object;
        rs.objState = ObjectState::Start;
    }
    else if (vt == ValueType::Error)
    {
        rs.state = MyState::Error;
    }
    else
    {
        /** for normal array element value, then pop it from stack */
        popValue();
        rs.arrayState = ArrayState::Element;
    }
}


bool MyReader3::parse(const char* pStart, const char* pEnd, Value& root)
{
    mIsErrorOccur = false;
    SkipSpaces(pStart, pEnd);
    ReadState rs(MyState::Start);

    if (pStart < pEnd)
    {
        mRootValue = &root;
        pushValue(root); /** push root value to value stack */

        while ((pStart < pEnd) && (rs.state != MyState::End))
        {
            switch (rs.state)
            {
            case MyState::Start:  rs = onStart(pStart, pEnd); break;
            case MyState::Object: rs = onObject(rs, pStart, pEnd); break;
            case MyState::Array:  rs = onArray(rs, pStart, pEnd); break;
            case MyState::Error:  rs = onError(pStart, pEnd); break;
            default:
                break;
            }
        }

        if (rs.state == MyState::End)
        {
            if (pStart < pEnd)
            {
                SkipSpaces(pStart, pEnd);
                char ch = GetNextChar(pStart, pEnd);

                if (ch != '\0')
                {
                    LOGE("Extra non-whitespace(%c) after JSON value.\n", ch);
                    rs = onError(pStart, pEnd);
                }
            }
        }
        else
        {
            rs = onError(pStart, pEnd);
        }
    }
    else
    {
        mIsErrorOccur = true; /** empty document */
    }

    return  !mIsErrorOccur;
}

/******************************************************************************
 **    FUNCTION DEFINITIONS
 ******************************************************************************/
 /**\brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
  * \param document UTF-8 encoded string containing the document to read.
  * \param root [out] Contains the root value of the document if it was
  *                   successfully parsed.
  *
  * \return true: if the document was successfully parsed,
  *         false: if an error occurred.
  */
bool JsonParse(const std::string& document, Value& root)
{
    MyReader3 mr;
    return mr.parse(document.c_str(), document.c_str() + document.size(), root);
}


/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
 * \param beginDoc [in] Pointer on the beginning of the UTF-8 encoded string
 *                      of the document to read.
 * \param endDoc   [in] Pointer on the end of the UTF-8 encoded string of the
 *                      document to read.
 * \param root [out] Contains the root value of the document if it was
 *                   successfully parsed.
 *
 * \return true: if the document was successfully parsed,
 *         false: if an error occurred.
 */
bool JsonParse(const char* beginDoc, const char* endDoc, Value& root)
{

    MyReader3 mr;
    return mr.parse(beginDoc, endDoc, root);
}

} /** namespace dog */
